package com.gengzp.common.utils;

import java.util.concurrent.atomic.AtomicLong;

/**
 * @ClassName SnowflakeIdGenerator
 * @Description 雪花算法id生成器（优化版，解决批量生成重复ID问题）
 * @Author gengzp
 * @Date 2025/5/11 16:10
 */
public class SnowflakeIdGenerator {

    // 起始时间戳（例如：2020-01-01）
    private final static long START_STAMP = 1577836800000L;

    // 每部分位数分配 - 调整分配比例以适应更多节点
    private final static long SEQUENCE_BIT = 12; // 序列号位数 (4096/毫秒)
    private final static long WORKER_BIT = 5;    // 工作节点位数 (32)
    private final static long DATA_CENTER_BIT = 5; // 数据中心位数 (32)

    // 剩余位数自动分配给时间戳，无需显式定义

    // 最大值掩码
    private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);
    private final static long MAX_WORKER = ~(-1L << WORKER_BIT);
    private final static long MAX_DATA_CENTER = ~(-1L << DATA_CENTER_BIT);

    // 位移量计算
    private final static long WORKER_LEFT = SEQUENCE_BIT;
    private final static long DATA_CENTER_LEFT = WORKER_LEFT + WORKER_BIT;
    private final static long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;

    // 数据中心ID和工作节点ID
    private final long dataCenterId;
    private final long workerId;

    // 上次生成ID的时间戳
    private final AtomicLong lastTimestamp = new AtomicLong(-1L);

    // 当前序列号
    private final AtomicLong sequence = new AtomicLong(0);

    /**
     * 构造函数
     * @param workerId 工作节点ID
     * @param dataCenterId 数据中心ID
     */
    public SnowflakeIdGenerator(long workerId, long dataCenterId) {
        if (workerId < 0 || workerId > MAX_WORKER) {
            throw new IllegalArgumentException("Worker ID must be between 0 and " + MAX_WORKER);
        }
        if (dataCenterId < 0 || dataCenterId > MAX_DATA_CENTER) {
            throw new IllegalArgumentException("DataCenter ID must be between 0 and " + MAX_DATA_CENTER);
        }
        this.workerId = workerId;
        this.dataCenterId = dataCenterId;
    }

    // 单例持有者
    private static class SingletonHolder {
        // 默认工作节点ID和数据中心ID，实际使用时应根据部署环境动态配置
        private static final SnowflakeIdGenerator INSTANCE = new SnowflakeIdGenerator(
                getWorkerId(), getDatacenterId());

        // 获取工作节点ID的方法，可以根据实际环境实现
        private static long getWorkerId() {
            // 实际应用中应从配置中心或环境变量获取
            return 1;
        }

        // 获取数据中心ID的方法，可以根据实际环境实现
        private static long getDatacenterId() {
            // 实际应用中应从配置中心或环境变量获取
            return 1;
        }
    }

    /**
     * 获取单例实例
     */
    public static SnowflakeIdGenerator getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     * 生成唯一ID
     */
    public long nextId() {
        long timestamp = getCurrentTimestamp();

        // 如果当前时间小于上一次ID生成的时间戳，说明系统时钟回退过，这是不允许的
        if (timestamp < lastTimestamp.get()) {
            throw new RuntimeException(String.format(
                    "Clock moved backwards. Refusing to generate id for %d milliseconds",
                    lastTimestamp.get() - timestamp));
        }

        // 如果是同一时间生成的，则进行序列号自增
        if (lastTimestamp.get() == timestamp) {
            // 原子操作确保序列号递增的线程安全性
            long nextSequence = sequence.incrementAndGet() & MAX_SEQUENCE;

            // 如果序列号达到最大值，则等待下一个毫秒
            if (nextSequence == 0) {
                timestamp = waitNextMillis(lastTimestamp.get());
            }
        } else {
            // 如果是新的毫秒，重置序列号
            sequence.set(0);
        }

        // 更新上次生成ID的时间戳
        lastTimestamp.set(timestamp);

        // 组合并返回ID
        return ((timestamp - START_STAMP) << TIMESTAMP_LEFT)
                | (dataCenterId << DATA_CENTER_LEFT)
                | (workerId << WORKER_LEFT)
                | sequence.get();
    }

    /**
     * 批量生成ID
     * @param count 需要生成的ID数量
     * @return 生成的ID数组
     */
    public long[] nextIds(int count) {
        if (count <= 0 || count > 1000) { // 限制最大批量数量，防止内存溢出
            throw new IllegalArgumentException("Count must be between 1 and 1000");
        }

        long[] ids = new long[count];
        for (int i = 0; i < count; i++) {
            ids[i] = nextId();
        }
        return ids;
    }

    /**
     * 获取当前毫秒时间戳
     */
    private long getCurrentTimestamp() {
        return System.currentTimeMillis();
    }

    /**
     * 等待到下一个毫秒
     */
    private long waitNextMillis(long lastTimestamp) {
        long timestamp = getCurrentTimestamp();
        while (timestamp <= lastTimestamp) {
            timestamp = getCurrentTimestamp();
        }
        return timestamp;
    }

    /**
     * 提供给外部调用的静态方法
     */
    public static long generateId() {
        return getInstance().nextId();
    }

    /**
     * 批量生成ID的静态方法
     */
    public static long[] generateIds(int count) {
        return getInstance().nextIds(count);
    }
}
